#include "StdAfx.h"
#include "Icmp.h"

CIcmp::CIcmp()
{
	m_hICmp = IcmpCreateFile();
	m_hwndCallback = NULL;
}

CIcmp::~CIcmp()
{
	IcmpCloseHandle(m_hICmp);
}

void CIcmp::SetCallback(HWND hwndCallback)
{
	m_hwndCallback = hwndCallback;
}

LONG CIcmp::Ping(LPCTSTR lpszAddress)
{
	m_sAddress = lpszAddress;
	AfxBeginThread(_DoPingThread, this);

	return ERROR_SUCCESS;

}

LONG CIcmp::TraceRoute(LPCTSTR lpszAddress)
{
	m_sAddress = lpszAddress;
	AfxBeginThread(_DoTraceRouteThread, this);
	return ERROR_SUCCESS;
}

LONG CIcmp::_Ping(DWORD addr, ip_option_information* pOptionInfo, icmp_echo_reply* pReply)
{
	DWORD dw = IcmpSendEcho(m_hICmp, addr, 0,0, pOptionInfo, pReply, sizeof(icmp_echo_reply),5000);
	if(0 == dw)
	{
		return GetLastError();
	}

	return ERROR_SUCCESS;
}

UINT CIcmp::_DoPingThread(LPVOID pParam)
{
	CIcmp* pThis = (CIcmp*)pParam;
	return pThis->_ExecutePingThread();
}

UINT CIcmp::_ExecutePingThread()
{
	char szHost[256];
	ustrncpy(szHost, m_sAddress, 256);

	DWORD dwAddress = inet_addr(szHost);
	if(INADDR_NONE == dwAddress)
	{
		hostent* host = gethostbyname(szHost);
		if(host)
			memcpy(&dwAddress, host->h_addr, host->h_length);
		else
			return _PostPingError();
	}

	CIcmpReply* pReply = new CIcmpReply;
	pReply->m_dwAddress = dwAddress;
	pReply->m_dwError = _Ping(dwAddress, NULL, pReply);
	PostMessage(m_hwndCallback, UWM_PING_REPLY, 0, (LPARAM)pReply);

	return ERROR_SUCCESS;
}

UINT CIcmp::_DoTraceRouteThread(LPVOID pParam)
{
	CIcmp* pThis = (CIcmp*)pParam;
	return pThis->_ExecuteTraceRouteThread();
}

UINT CIcmp::_ExecuteTraceRouteThread()
{
	for (int nIdx = 1; nIdx<= 99; nIdx++)
	{
		if (m_oIcmpReply.m_dwAddress == m_oIcmpReply.Address)
		{
			break;
		}

		char szHost[256];
		ustrncpy(szHost, m_sAddress, 256);

		
		DWORD dwAddress = inet_addr(szHost);
		if(INADDR_NONE == dwAddress)
		{
			hostent* host = gethostbyname(szHost);
			if(host)
				memcpy(&dwAddress, host->h_addr, host->h_length);
			else
				return _PostTraceRouteError();
		}

		CIcmpReply* pReply = new CIcmpReply;
		pReply->m_dwAddress = dwAddress;
		ip_option_information ioi;
		memset(&ioi, 0, sizeof(ip_option_information));
		ioi.Ttl = nIdx;

		pReply->m_dwError = _Ping(dwAddress, &ioi, pReply);
		m_oIcmpReply = *pReply;
		PostMessage(m_hwndCallback, UWM_TRACEROUTE_REPLY, 0, (LPARAM)pReply);
	}
	return ERROR_SUCCESS;
}

UINT CIcmp::_PostPingError()
{
	int nError = WSAGetLastError();

	CIcmpReply* pReply = new CIcmpReply;
	pReply->m_dwAddress = INADDR_NONE;
	pReply->m_dwError = nError;
	PostMessage(m_hwndCallback, UWM_PING_REPLY, 0, (LPARAM)pReply);

	return nError;
}

UINT CIcmp::_PostTraceRouteError()
{
	int nError = WSAGetLastError();

	CIcmpReply* pReply = new CIcmpReply;
	pReply->m_dwAddress = INADDR_NONE;
	pReply->m_dwError = nError;
	PostMessage(m_hwndCallback, UWM_TRACEROUTE_REPLY, 0, (LPARAM)pReply);

	return nError;
}
